/**
 * 食用方法
 *
 * 设置策略方法
 * setStrategy({
 *     isNotEmpty (value, errMsg) {
 *
 *     },
 *     minLength (value, length, errMsg) {
 *
 *     }
 * })
 *
 * 添加单个验证 单个规则
 * addRule('userName', {
 *     strategy: 'isNotEmpty',
 *     errMsg: '用户名不成为空',
 * })
 * 添加单个验证 多个规则
 * addRule('userName', [
 *  {
 *     strategy: 'isNotEmpty',
 *     errMsg: '用户名不成为空',
 *  },
 *  {
 *     strategy: 'minLength:10',
 *     errMsg: '用户名称不能小于10个字符',
 * }
 * ])
 * 添加多个验证
 * addRule({
 *     userName: '张三',
 *     pass: '123456',
 * }, {
 *     userName: [
 *         {
 *             strategy: 'isNotEmpty',
 *             errMsg: '用户名不成为空',
 *         },
 *     ],
 *     pass: [
 *         {
 *             strategy: 'isNotEmpty',
 *             errMsg: '密码不成为空',
 *         },
 *         {
 *             strategy: 'minLength',
 *             errMsg: '密码称不能小于10个字符',
 *         },
 *     ]
 * })
 *
 * 开始验证
 * start(result => {
 *     console.log(result)
 * })
 */

import Utils from './utils'

class FormValidate extends Utils {
    // 验证列表
    validateList = []

    constructor () {
        super()
    }

    /**
     * 设置 策略方法
     * 该方法允许覆盖掉已有的方法 (不过要遵循传参方式)
     * @param {Object} strategies 策略对象
     */
    setStrategy (strategies) {
        Object.assign(this.strategies, strategies)
    }

    /**
     * 添加验证规则
     * @param {String, Object} value 验证单个是一个String 多个是一个Object
     * @param {Object} rules 验证规则
     */
    addRule (value='', rules={}) {
        super.isType(value, 'String') ? this.validateSingle(value, rules) : this.rulesValidateMultiple(value, rules)
    }

    /**
     * 开始验证
     */
    start (callback) {
        // 存放验证失败的提示文本
        let msg = ''
        let errMsg = this.validateList.some((fn, index) => {
            let err = fn()
            // 如果 err 有值说明验证没通过，结束循环
            return err && (msg = err)
        })

        // 把信息回调出去
        callback(msg ? { state: true, errMsg: msg } : { state: false, errMsg: msg })
        // 释放列表
        this.validateList = []
    }

    /**
     * 验证单个
     * @param {String} value 要验证的值
     * @param {Object} rules 要验证的规则
     */
    validateSingle (value, rules) {
        // 该字段只能为Object || Array
        if (!['Object', 'Array'].includes(super.getType(rules))) throw new Error('验证规则的数据类型只能为 Object 或 Array')

        super.isType(rules, 'Object') ? this.rulesSingle(value, rules) : this.rulesMultiple(value, rules)
    }

    /**
     * 验证多个
     * @param {Object} valueObj 要验证的所有字段 （必须是一个对象）
     * @param {Object} rules 要验证的规则字段 （必须是一个数组）
     */
    rulesValidateMultiple (valueObj, rules) {
        Object.keys(rules).map(name => {
            if (!Object.keys(valueObj).includes(name)) throw new Error(`找不到${name}, 请查看\n${JSON.stringify(valueObj, null, '\t')}\n里有没有${name}字段`)
            this.rulesMultiple(valueObj[name], rules[name])
        })
    }

    /**
     * 单条规则
     * @param {String} value
     * @param {Object} rule
     */
    rulesSingle (value, rule) {
        let { strategy, errMsg } = rule
        let arr = strategy.split(':')
        strategy = arr.shift()

        // 防止用户传的参数带着 :
        let str = arr.join(':')
        arr = str ? [str] : []

        arr.unshift(value)
        arr.push(errMsg)
        this.validateList.push(() => this.strategies[strategy].apply(this, arr) )
    }

    /**
     * 多条规则
     * @param {String} value
     * @param {Array} rules
     */
    rulesMultiple (value, rules) {
        rules.map(rule => {
            this.rulesSingle(value, rule)
        })
    }
}

/**
 * 原型
 */
Object.assign(FormValidate.prototype, {
    /**
     * 该策略对象发放规则
     * 第一个参数为 要验证的值
     * 第二个参数为
     *      如果又该参数  该参数为 :右边的值  比如 isNotEmpty:aaa （第二个参数为aaa） 这里理论上可以携带各种参数 JSON.stringify()包一下
     *      如果没有该参数  该参数为 第三个参数
     * 第三个参数为 验证失败的提示文本
     * @param {return} 验证失败的提示文本 (必须return出去)
     */
    strategies: {
        /**
         * 判断不为空
         */
        isNotEmpty (value, errMsg) {
            if (!value) return errMsg
        },

        /**
         * 判断最小长度
         */
        minLength (value, length, errMsg) {
            if (value.length < length) return errMsg
        },

        /**
         * 判断最大长度
         */
        maxLength (value, length, errMsg) {
            if (value.length > length) return errMsg
        },
        /**
         * 验证手机
         */
        isMobile (value, params, errMsg) {
            // console.log(value)
            // console.log(params)
            // console.log(errMsg)
        }
    }
})

export default FormValidate
